#include "IpcMsgHelper.h"
#include "UIIpcClient.h"
#include <vector>
#include <string>
#include "request_generated.h"
#include "response_generated.h"
#include "wubi_def_generated.h"
#include "ui_msg_def.h"

using namespace WubiUIMsg;

static char *g_buffer = new char[UI_PIPE_SIZE];


bool SendReceive(UIIpcClient *client, const flatbuffers::FlatBufferBuilder &fbb, std::vector<UIBaseInfo> &outList)
{
    DWORD written = 0;
    if (!client->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written))
    {
        return false;
    }

    
    DWORD read = 0;
    if (!client->readBuffer(g_buffer, UI_PIPE_SIZE, &read))
    {
        return false;
    }

    auto response = GetUIResponse(g_buffer);
    if (!response->result())
    {
        return false;
    }

    if (response->result_data_type() == UIRspParam_UIRspSchemeList)
    {
        auto list = response->result_data_as_UIRspSchemeList();
        for (auto item : *list->schemes())
        {
            UIBaseInfo info;
            info.id = item->id();
            info.name = item->name()->str();
            info.candidate_count = item->candidate_count();
            outList.push_back(info);
        }
    }
    else if (response->result_data_type() == UIRspParam_UIRspCodeTableList)
    {
        auto list = response->result_data_as_UIRspCodeTableList();
        for (auto item : *list->tables())
        {
            UIBaseInfo info;
            info.id = item->id();
            info.name = item->name()->str();
            info.enable = item->enable();
            outList.push_back(info);
        }
    }
    return true;
}

// 获取所有输入法方案
bool IpcMsgHelper::getAllSchemes(std::vector<UIBaseInfo> &schemes)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto req = CreateUIRequest(fbb, WubiCmd_GetAllSchemes,
                               UIReqParam_UIReqGetSchemes, CreateUIReqGetSchemes(fbb).Union());
    fbb.Finish(req);
    return SendReceive(_ipc_clent, fbb, schemes);
}

// 创建新方案
bool IpcMsgHelper::createScheme(const std::string &name, unsigned int &newId)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqCreateScheme(fbb, fbb.CreateString(name));
    auto req = CreateUIRequest(fbb, WubiCmd_CreateScheme,
                               UIReqParam_UIReqCreateScheme, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written))
    {
        return false;
    }

    
    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read))
    {
        return false;
    }

    auto response = GetUIResponse(g_buffer);
    if (response->result_data_type() == UIRspParam_UIRspCreateScheme)
    {
        newId = response->result_data_as_UIRspCreateScheme()->new_id();
    }
    return response->result();
}

// 更新方案设置
bool IpcMsgHelper::updateScheme(unsigned int id, const std::string &name, int candidateCount)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqUpdateScheme(fbb, id, fbb.CreateString(name), candidateCount);
    auto req = CreateUIRequest(fbb, WubiCmd_UpdateScheme,
                               UIReqParam_UIReqUpdateScheme, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written))
    {
        return false;
    }

    
    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read))
    {
        return false;
    }
    return GetUIResponse(g_buffer)->result();
}

// 删除方案
bool IpcMsgHelper::deleteScheme(unsigned int id)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqDeleteScheme(fbb, id);
    auto req = CreateUIRequest(fbb, WubiCmd_DeleteScheme,
                               UIReqParam_UIReqDeleteScheme, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written))
    {
        return false;
    }

    
    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read))
    {
        return false;
    }
    return GetUIResponse(g_buffer)->result();
}

// 获取指定方案的码表列表
bool IpcMsgHelper::getCodeTables(unsigned int schemeId, std::vector<UIBaseInfo> &tables)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqGetCodeTables(fbb, schemeId);
    auto req = CreateUIRequest(fbb, WubiCmd_getCodeTables,
                               UIReqParam_UIReqGetCodeTables, params.Union());
    fbb.Finish(req);
    return SendReceive(_ipc_clent, fbb, tables);
}

// 添加码表
bool IpcMsgHelper::addCodeTable(unsigned int schemeId, const std::string &name,
                                const std::string &filePath, unsigned int &newTableId)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqAddCodeTable(fbb, schemeId,
                                          fbb.CreateString(name), fbb.CreateString(filePath));
    auto req = CreateUIRequest(fbb, WubiCmd_AddCodeTable,
                               UIReqParam_UIReqAddCodeTable, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written))
    {
        return false;
    }

    
    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read))
    {
        return false;
    }

    auto response = GetUIResponse(g_buffer);
    if (response->result_data_type() == UIRspParam_UIRspAddCodeTable)
    {
        newTableId = response->result_data_as_UIRspAddCodeTable()->new_table_id();
    }
    return response->result();
}

// 设置当前方案
bool IpcMsgHelper::setCurrentSchemeId(unsigned int id)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqSetCurrentSchemeId(fbb, id);
    auto req = CreateUIRequest(fbb, WubiCmd_SetCurrentSchemeId,
                               UIReqParam_UIReqSetCurrentSchemeId, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written))
    {
        return false;
    }

    
    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read))
    {
        return false;
    }
    return GetUIResponse(g_buffer)->result();
}

// 获取候选词列表
bool IpcMsgHelper::getCandidateList(const std::string &code, std::vector<std::string> &candidates)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqGetCandidateList(fbb, fbb.CreateString(code));
    auto req = CreateUIRequest(fbb, WubiCmd_GetCandidateList,
                               UIReqParam_UIReqGetCandidateList, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written))
    {
        return false;
    }

    
    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read))
    {
        return false;
    }

    auto response = GetUIResponse(g_buffer);
    if (response->result_data_type() == UIRspParam_UIRspCandidateList)
    {
        auto list = response->result_data_as_UIRspCandidateList();
        for (auto item : *list->candidates())
        {
            candidates.push_back(item->str());
        }
    }
    return response->result();
}

// 获取当前方案ID
bool IpcMsgHelper::getCurrentSchemeId(unsigned int &outId)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqGetCurrentSchemeId(fbb);
    auto req = CreateUIRequest(fbb, WubiCmd_GetCurrentSchemeId,
                               UIReqParam_UIReqGetCurrentSchemeId, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written))
    {
        return false;
    }

    
    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read))
    {
        return false;
    }

    auto response = GetUIResponse(g_buffer);
    if (response->result_data_type() == UIRspParam_UIRspGetCurrentSchemeId)
    {
        outId = response->result_data_as_UIRspGetCurrentSchemeId()->id();
    }
    return response->result();
}

// 重新加载词库
bool IpcMsgHelper::reloadWordDic()
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqReloadWordDic(fbb);
    auto req = CreateUIRequest(fbb, WubiCmd_ReloadWordDic,
                               UIReqParam_UIReqReloadWordDic, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written))
    {
        return false;
    }

    
    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read))
    {
        return false;
    }
    return GetUIResponse(g_buffer)->result();
}

// 移除码表
bool IpcMsgHelper::removeCodeTable(unsigned int schemeId, unsigned int codeTableId)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqRemoveCodeTable(fbb, schemeId, codeTableId);
    auto req = CreateUIRequest(fbb, WubiCmd_RemoveCodeTable,
                               UIReqParam_UIReqRemoveCodeTable, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written))
    {
        return false;
    }

    
    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read))
    {
        return false;
    }
    return GetUIResponse(g_buffer)->result();
}

// 交换两个码表顺序
bool IpcMsgHelper::swapCodeTableOrder(unsigned int id1, unsigned int id2)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqSwapCodeTableOrder(fbb, id1, id2);
    auto req = CreateUIRequest(fbb, WubiCmd_SwapCodeTableOrder,
                               UIReqParam_UIReqSwapCodeTableOrder, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written)) {
        return false;
    }

    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read)) {
        return false;
    }
    return GetUIResponse(g_buffer)->result();
}

// 获取码表内指定编码的词组
bool IpcMsgHelper::getCodeTableDataByCode(unsigned int codeTableId, const std::string& code, 
                                        std::vector<WubiCodetableData>& outData)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqGetCodeTableDataByCode(fbb, codeTableId, fbb.CreateString(code));
    auto req = CreateUIRequest(fbb, WubiCmd_GetCodeTableDataByCode,
                               UIReqParam_UIReqGetCodeTableDataByCode, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written)) {
        return false;
    }

    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read)) {
        return false;
    }

    auto response = GetUIResponse(g_buffer);
    if (response->result_data_type() == UIRspParam_UIRspGetCodeTableDataByCode) {
        auto list = response->result_data_as_UIRspGetCodeTableDataByCode();
        for (auto item : *list->words()) {
            WubiCodetableData data;
            data.id = item->id();
            data.word = item->word()->str();
            outData.push_back(data);
        }
    }
    return response->result();
}

// 交换码表内词语顺序
bool IpcMsgHelper::swapCodeTableDataOrder(unsigned int codeTableId, 
                                        unsigned int codeId1, unsigned int codeId2)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqSwapCodeTableDataOrder(fbb, codeTableId, codeId1, codeId2);
    auto req = CreateUIRequest(fbb, WubiCmd_SwapCodeTableDataOrder,
                               UIReqParam_UIReqSwapCodeTableDataOrder, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written)) {
        return false;
    }

    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read)) {
        return false;
    }
    return GetUIResponse(g_buffer)->result();
}

// 添加词条
bool IpcMsgHelper::addWord(unsigned int codeTableId, const std::string& code,
                         const std::string& word, unsigned int& newCodeId)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqAddWord(fbb, codeTableId, 
                                   fbb.CreateString(code), fbb.CreateString(word));
    auto req = CreateUIRequest(fbb, WubiCmd_AddWord,
                               UIReqParam_UIReqAddWord, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written)) {
        return false;
    }

    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read)) {
        return false;
    }

    auto response = GetUIResponse(g_buffer);
    if (response->result_data_type() == UIRspParam_UIRspAddWord) {
        newCodeId = response->result_data_as_UIRspAddWord()->new_code_id();
    }
    return response->result();
}

// 删除词条
bool IpcMsgHelper::removeWord(unsigned int codeId)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqRemoveWord(fbb, codeId);
    auto req = CreateUIRequest(fbb, WubiCmd_RemoveWord,
                               UIReqParam_UIReqRemoveWord, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written)) {
        return false;
    }

    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read)) {
        return false;
    }
    return GetUIResponse(g_buffer)->result();
}

// 新增码表启用状态设置方法
bool IpcMsgHelper::setCodeTableEnable(unsigned int codeTableId, bool enable)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqSetCodeTableEnable(fbb, codeTableId, enable);
    auto req = CreateUIRequest(fbb, WubiCmd_SetCodeTableEnable,
                               UIReqParam_UIReqSetCodeTableEnable, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written)) {
        return false;
    }

    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read)) {
        return false;
    }
    return GetUIResponse(g_buffer)->result();
}

// 编码反查实现
bool IpcMsgHelper::getCodeByWord(const std::string& word, std::vector<std::string>& out_codes)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqGetCodeByWord(fbb, fbb.CreateString(word));
    auto req = CreateUIRequest(fbb, WubiCmd_GetCodeByWord,
                               UIReqParam_UIReqGetCodeByWord, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written)) {
        return false;
    }

    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read)) {
        return false;
    }

    auto response = GetUIResponse(g_buffer);
    if (response->result_data_type() == UIRspParam_UIRspGetCodeByWord) {
        auto codes = response->result_data_as_UIRspGetCodeByWord()->codes();
        for (auto code : *codes) {
            out_codes.push_back(code->str());
        }
    }
    return response->result();
}

// 导出码表实现
bool IpcMsgHelper::exportCodeTable(unsigned int codeTableId, const std::string& filePath)
{
    flatbuffers::FlatBufferBuilder fbb;
    auto params = CreateUIReqExportCodeTable(fbb, codeTableId, fbb.CreateString(filePath));
    auto req = CreateUIRequest(fbb, WubiCmd_ExportCodeTable,
                               UIReqParam_UIReqExportCodeTable, params.Union());
    fbb.Finish(req);

    DWORD written = 0;
    if (!_ipc_clent->sendBuffer(fbb.GetBufferPointer(), fbb.GetSize(), &written)) {
        return false;
    }

    DWORD read = 0;
    if (!_ipc_clent->readBuffer(g_buffer, UI_PIPE_SIZE, &read)) {
        return false;
    }
    return GetUIResponse(g_buffer)->result();
}